﻿using System;
using System.ComponentModel.DataAnnotations;
using System.Net.Http;
using DotNetStar.OpenSDK.Payment;
using Newtonsoft.Json;

namespace DotNetStar.OpenSDK.WeChat.Pay
{
    /// <summary>
    /// 支付统一下单请求。适用于 H5支付/APP支付/公众平台支付/扫码支付。
    /// </summary>
    /// <seealso cref="Payment.PaymentApiRequest{UnifiedOrderApiResponse}" />
    /// <remarks>
    /// 商户系统先调用该接口在微信支付服务后台生成预支付交易单，返回正确的预支付交易回话标识后再在APP里面调起支付。
    /// </remarks>
    /// <seealso cref="Payment.PaymentApiRequest{UnifiedOrderApiResponse}" />    
    public class UnifiedOrderApiRequest : WeChatPayApiRequest<UnifiedOrderApiResponse>
    {
        /// <summary>
        /// 初始化 <see cref="UnifiedOrderApiRequest"/> 类的新实例。
        /// </summary>
        /// <param name="config">支付配置。</param>
        /// <param name="requestUrl">统一下单的 api 地址。若使用了沙箱地址，可以传入沙箱地址的 url。</param>
        public UnifiedOrderApiRequest(PaymentConfig config, string requestUrl = "https://api.mch.weixin.qq.com/pay/unifiedorder")
            : base(requestUrl, config)
            => this.Nonce_Str = Guid.NewGuid().ToString().Replace("-", string.Empty);

        #region 属性
        /// <summary>
        /// 附加数据，在查询API和支付通知中原样返回，该字段主要用于商户携带订单的自定义数据
        /// </summary>
        [StringLength(127)]
        public string Attach { get; set; }

        /// <summary>
        /// 商品简单描述，该字段请按照规范传递，具体请见 https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=4_2
        /// </summary>
        [Required, StringLength(128)]
        public string Body { get; set; }

        /// <summary>
        /// 商品详细描述，对于使用单品优惠的商户，必须按照规范上传 https://pay.weixin.qq.com/wiki/doc/api/danpin.php?chapter=9_102&amp;index=2
        /// </summary>
        [StringLength(8192)]
        public string Detail { get; set; }

        /// <summary>
        /// 终端设备号(门店号或收银设备ID)，注意：PC网页或公众号内支付请传"WEB"
        /// </summary>
        public string Device_Info { get; set; } = "WEB";

        /// <summary>
        /// 货币类型，默认 CNY。
        /// </summary>
        /// <remarks>默认人民币：CNY</remarks>
        [StringLength(16)]
        public string Fee_Type { get; set; } = "CNY";

        /// <summary>
        /// 订单优惠标记，代金券或立减优惠功能的参数 https://pay.weixin.qq.com/wiki/doc/api/tools/sp_coupon.php?chapter=12_1
        /// </summary>
        [StringLength(32)]
        public string Goods_Tag { get; set; }

        /// <summary>
        /// 指定支付方式。no_credit--指定不能使用信用卡支付（默认）。信用卡类型参见 https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=4_2
        /// </summary>
        [StringLength(32)]
        public string Limit_Pay { get; set; } = "no_credit";

        /// <summary>
        /// 通知地址，接收微信支付异步通知回调地址，通知url必须为直接可访问的url，不能携带参数。
        /// </summary>
        [StringLength(256)]
        public string Notify_Url { get; set; }
        

        /// <summary>
        /// 场景信息
        /// </summary>
        /// <remarks>
        /// 该字段用于统一下单时上报场景信息，目前支持上报实际门店信息。
        /// </remarks>
        /// <example>
        /// {
        ///     "store_id": "", //门店唯一标识，选填，String(32)
        ///     "store_name":"”//门店名称，选填，String(64)
        ///  }
        /// </example>
        [StringLength(256)]
        public string Scene_Info { get; set; }        

        /// <summary>
        /// 获取用户端实际ip
        /// </summary>
        [Required]
        public string Spbill_Create_Ip { get; set; }

        /// <summary>
        /// 订单失效时间，格式为yyyyMMddHHmmss，如2009年12月27日9点10分10秒表示为20091227091010
        /// </summary>
        [StringLength(14)]
        public string Time_Expire { get; set; }

        /// <summary>
        /// 订单生成时间，格式为 yyyyMMddHHmmss，如2009年12月25日9点10分10秒表示为20091225091010
        /// </summary>
        [StringLength(14)]
        public string Time_Start { get; set; }

        /// <summary>
        /// 获取订单总金额，单位为分
        /// </summary>
        [Required]
        public int Total_Fee { get; set; }

        /// <summary>
        /// 交易类型。
        /// </summary>
        [Required, StringLength(16)]
        public TradeTypes Trade_Type { get; set; } = TradeTypes.NATIVE;
        
        /// <summary>
        /// 商品ID。<see cref="Trade_Type"/>=NATIVE时（即扫码支付），此参数必传。此参数为二维码中包含的商品ID，商户自行定义。
        /// </summary>
        [StringLength(32)]
        public string Product_Id { get; set; }

        /// <summary>
        /// <see cref="Trade_Type"/> 是 JSAPI 时（即公众号支付），此参数必传，此参数为微信用户在商户对应appid下的唯一标识。
        /// </summary>
        [StringLength(128)]
        public string OpenId { get; set; }        
        #endregion

        /// <summary>
        /// 生成签名时不能带 sign 参数。
        /// 然后动态添加 sign 参数并转换为 xml。
        /// </summary>
        /// <param name="keyValue"><see cref="T:DotNetStar.OpenSDK.KeyValueCollection" /> 实例的动态对象，查看文档了解用法。</param>
        /// <returns>
        /// 微信 app 支付的 xml 格式字符串。
        /// </returns>
        public override dynamic OnArgumentsCreating(dynamic keyValue)
        {
            keyValue.sign = this.SignatureHasher.GenerateSignature(this);
            return keyValue.xml();
        }

        /// <summary>
        /// Processes the response callback.
        /// </summary>
        /// <param name="httpResponse">The HTTP response.</param>
        /// <returns></returns>
        public override UnifiedOrderApiResponse ResponseHandler(HttpResponseMessage httpResponse)
        {
            var response = httpResponse.GetContentAsString();
            return new KeyValueCollection(response).ToObject<UnifiedOrderApiResponse>();
        }
    }
}
